/*
 * TablaSimbolos.java
 *
 * Created on 8 de marzo de 2008, 17:53
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package TablaDeSimbolos;
import java.util.ArrayList;
import java.util.HashMap;

//********************* ANTES ESTABA import Semantico.ExpresionTipo;
/**
 *
 * @author Martín
 */
public class TablaSimbolos {
    
	private ArrayList<Integer> listaPadres;
	private ArrayList<HashMap<String, Atributos>> listaTablas;
    //private HashMap<String, Atributos> tabla;
    private int iTablaActual;
    private boolean blnPermitidaEscritura;
    
    /** Creates a new instance of TablaSimbolos */
    /**
     *Crea una tabla de símbolos cuyo padre o tabla continente es
     *"tablaPadre".
     *Para crear la primera tabla de nivel cero se indica "tablaPadre" null
     */
    public TablaSimbolos(TablaSimbolos tablaPadre) {
    	listaTablas = new ArrayList<HashMap<String,Atributos>>();
    	listaPadres = new ArrayList<Integer>();
    	HashMap<String, Atributos> principal = new HashMap<String, Atributos>();
    	listaPadres.add(null); // El primer nivel no posee padre
    	listaTablas.add(principal); // Añade la tabla principal
    	
    	iTablaActual = 0;
    	//TODO: permitida la escritura por defecto, pero esto puede y debe cambiar.
    	blnPermitidaEscritura = true;
        //tabla = new HashMap<String, Atributos>();
        //padre=tablaPadre;
    }
    
    /**
     *Inserta el token en la tabla.
     *lexema es el lexema del token y tipoToken es el tipo de token
     */
    public Atributos insertar(String lexema,Object tipoToken){
    	// Si no se permiten escrituras se retorna:
    	// 	- La entrada en la TS si existe previamente.
    	// 	- null si el lexema no existe en la TS.
    	if (!blnPermitidaEscritura) {
    		return this.buscar(lexema);
    	}
    	if (this.listaTablas.get(iTablaActual).containsKey(lexema)){ // Ya existe
    		return this.buscar(lexema);
    	}
    	if (this.buscar(lexema) != null){ // Si es un tipo se retorna su entrada
    		Atributos at = this.buscar(lexema);
    		if ((Boolean)at.obtener("IDTIPO")){
    			return at;
    		}
    	}
        Atributos valores=new Atributos();
        valores.insertar(Atributos.LEXEMA,lexema);
        valores.insertar(Atributos.TIPO_TOKEN,tipoToken);
        listaTablas.get(iTablaActual).put(lexema, valores);
        //tabla.put(lexema,valores);
        return valores;
    }
    
    /**
     *Completa los campos asociados a la entrada "entrada" rellenando el campo "campo"
     *con un valor "valor" y devuelve un puntero a la entrada
     */
    public Object completa(Atributos entrada,String campo,Object valor){
        entrada.insertar(campo,valor);
        return entrada;
    }
    
    /**
     *Busca si esta el token de lexema lexema y si lo encuentra devuelve
     *un objeto Atributos que es un puntero a la entrada
     */
    public Atributos buscar(String lexema){
    	// Si está en el nivel actual
    	if (listaTablas.get(iTablaActual).containsKey(lexema)){
    		return listaTablas.get(iTablaActual).get(lexema);
    	} else { // Si no se busca por todos los padres
    		int numTabla = iTablaActual;
    		HashMap<String, Atributos> temp = listaTablas.get(numTabla);    		
    		while (numTabla != 0 && temp != null && !temp.containsKey(lexema)){
    			numTabla = listaPadres.get(numTabla);
    			temp = listaTablas.get(numTabla);
    		}
    		if (temp == null || temp.isEmpty()) return null; // No la ha encontrado
    		else return temp.get(lexema); // Sí la ha encontrado
    	}
        /*Set<String> claves=tabla.keySet();
        if(claves.contains(lexema))
            return tabla.get(lexema);
        return null;*/
    }
    
    /**
     *Devuelve el valor del campo "campo" asociado a la entrada "entrada"
     *Si no hay ningun campo denominado "campo" devuelve null
     */
    public Object consultar(Atributos entrada,String campo){
        return entrada.esta(campo);
    }
    
    /**
     *Crea una nueva tabla de símbolos hija de la actual y asociada al token cuya
     *entrada en la tabla de símbolos es "entrada" y la devuelve
     *
     *No hace falta guardar la tabla anterior ya que se puede recuperar
     *mediante la funcion damePadre
     */
    public void creaAmbito(){
    	HashMap<String, Atributos> nuevaTabla = new HashMap<String, Atributos>();
    	listaTablas.add(nuevaTabla);
    	listaPadres.add(iTablaActual);
    	iTablaActual = listaTablas.size() - 1;
        /*TablaSimbolos nueva=new TablaSimbolos(this);
        entrada.insertar(Atributos.CONTENIDO,nueva);
        return nueva;*/
    }
    
   /**
    * Cierra el ámbito.
    */
    public void cierraAmbito(){
    	iTablaActual = listaPadres.get(iTablaActual);
    }
    
    /**
     * Permite inserciones en la tabla de símbolos actual
     */
    public void activaEscritura(){
    	blnPermitidaEscritura = true;
    }
    
    /**
     * Inhabilita escrituras en la tabla de símbolos actual
     */
    public void desactivaEscritura(){
    	blnPermitidaEscritura = false;
    }

    
}
